home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
PC.C
< prev
next >
Wrap
Text File
|
1993-10-18
|
21KB
|
898 lines
/* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C */
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <dir.h>
#include <io.h>
#include <sys/stat.h>
#include <string.h>
#include <process.h>
#include <fcntl.h>
#include <alloc.h>
#include <stdarg.h>
#include <bios.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "socket.h"
#include "internet.h"
#include "iface.h"
#include "cmdparse.h"
#include "pc.h"
#include "proc.h"
#include "session.h"
#include "smtp.h"
#ifdef SCC
#include "scc.h"
#endif
#ifdef PACKET
#include "pktdrvr.h"
#endif
#ifdef ASY
#include "asy.h"
#include "n8250.h"
#endif
#include "domain.h"
#include "files.h"
#define DEL 0x7f
extern struct proc *Display;
extern int getproc __ARGS((void));
int Tick = 0;
static int32 Starttime;
int32 Clock;
/* This flag is set by setirq() if IRQ 8-15 is used, indicating
* that the machine is a PC/AT with a second 8259 interrupt controller.
* If this flag is set, the interrupt return code in pcgen.asm will
* send an End of Interrupt command to the second 8259 as well as the
* first.
*/
int Isat = 0;
static int saved_break;
#define KBSIZE 256 /* Keyboard input buffer */
static struct {
char buf[KBSIZE];
char *wp;
char *rp;
int cnt;
} Keyboard;
static int Swap = FALSE;
extern int do_spawn __ARGS((int swapping,char *execfname,char *cmdtail,unsigned envlen,char *envp));
extern int prep_swap __ARGS((unsigned method,char *swapfname));
/* Directly read BIOS count of time ticks. This is used instead of
* calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
* which resets the midnight overflow flag, losing days on the clock.
*/
static long near
bioscnt(void)
{
int i_state = dirps();
long rval = *(long far *)MK_FP(0x40,0x6c);
restore(i_state);
return rval;
}
static int err = 0;
/* define the error messages for trapping disk problems - D.Crompton
* ported into WNOS DB3FL.910407
*/
static int
handler(int errval,int ax,int bp,int si)
{
if(ax >= 0 && err == 0) {
char *crit_err_msg[] = {
"Write protect",
"Unknown unit",
"Not ready",
"Unknown command",
"Data error (CRC)",
"Bad request",
"Seek error",
"Unknown media type",
"Sector not found",
"Printer out of paper",
"Write fault",
"Read fault",
"General failure",
"Reserved",
"Reserved",
"Invalid disk change"
};
printf("%s on drive %c\n",
crit_err_msg[(_DI & 0x00FF)],(ax & 0x00FF) + 'A');
}
if(++err > 2) {
err = 0;
}
hardretn(3);
return 3;
}
/* Called at startup time to set up console I/O, memory heap */
void
ioinit(void)
{
/* Fail all I/O errors */
harderr(handler);
/* Save these two file table entries for something more useful */
Fclose(stdaux);
Fclose(stdprn);
/* this breaks tab expansion so you must use ANSI or NANSI */
ioctl(fileno(stdout), 1, (ioctl(fileno(stdout),0) & 0xff) | 0x20);
saved_break = getcbrk();
setcbrk(0);
Starttime = bioscnt();
/* Link timer handler into timer interrupt chain */
chtimer(btick);
/* Find out what multitasker we're running under, if any */
chktasker();
if(getproc() > 5)
Isat = 1;
/* Initialize keyboard queue */
Keyboard.cnt = 0;
Keyboard.rp = Keyboard.wp = Keyboard.buf;
}
/* Called just before exiting to restore console state */
void
iostop(void)
{
struct iface *ifp, *iftmp = NULLIF;
ioctl(fileno(stdout), 1, (ioctl(fileno(stdout), 0) & 0xff) & ~0x20);
setcbrk(saved_break);
for(ifp = Ifaces; ifp != NULLIF; ifp = iftmp) {
iftmp = ifp->next;
if_detach(ifp);
}
#ifdef SCC
sccstop(); /* reset int mask for all scc boards */
#endif
/* Unlink timer handler from timer chain */
uchtimer();
}
/*-----------------------------------------------------------------------*/
typedef struct {
struct text_info tr;
char *sbuf;
} Doslock;
static unsigned near dos_prepare(Doslock *dl);
static void near dos_restore(Doslock *dl);
static int do_exec __ARGS((char *xfn,char *pars,int spawn,unsigned needed));
/* Return codes (only upper byte significant) */
#define RC_PREPERR 0x0100
#define RC_NOFILE 0x0200
#define RC_EXECERR 0x0300
#define RC_ENVERR 0x0400
#define RC_SWAPERR 0x0500
/* Swap method and option flags */
#define USE_EMS 0x01
#define USE_XMS 0x02
#define USE_FILE 0x04
#define EMS_FIRST 0x00
#define XMS_FIRST 0x10
#define HIDE_FILE 0x40
#define NO_PREALLOC 0x100
#define CHECK_NET 0x200
#define USE_ALL (USE_EMS | USE_XMS | USE_FILE)
static int near
_spawn(char *env,char *def,int argc,char **argv)
{
Doslock dl;
int i, ret = 0;
char *p, *command = mxallocw(256);
if((p = getenv(env)) == NULL)
p = def;
dos_prepare(&dl);
if(argc > 1) {
if(*def == 'C') {
strcpy(command,"/c");
}
for(i = 1; i < argc; i++) {
strcat(command," ");
strcat(command,argv[i]);
}
}
if (!Swap || Mtasker) {
char *cp = mxallocw(256);
sprintf(cp,"%s %s",p,command);
ret = system(cp);
xfree(cp);
} else {
ret = do_exec(p,command,USE_ALL,0xffff);
}
dos_restore(&dl);
xfree(command);
return ret;
}
int
dobmail(int argc,char **argv,void *p)
{
int ret = _spawn("MAILER","BM.EXE",argc,argv);
/*-------------------------------------------------------------------*
* process Mailprompts *
*--------------------------------------------------------------------*/
smtptick(NULL); /* tickle smtp to send any mail */
return ret;
}
#ifdef XXX
/*----------------------------------------------------------------------*
* Spawn dg4dam's NNVIEW as subshell *
*-----------------------------------------------------------------------*/
int
donntpview(int argc,char **argv,void *p)
{
return _spawn("NNTPVIEW","NNTPVIEW.EXE",argc,argv);
}
#endif
int
doshell(int argc,char **argv,void *p)
{
return _spawn("COMSPEC","COMMAND.COM",argc,argv);
}
/* internal flags for prep_swap */
#define CREAT_TEMP 0x0080
#define DONT_SWAP_ENV 0x4000
static int
do_exec(char *exfn,char *epars,int spwn,unsigned needed)
{
char swapfn [82], execfn [82];
unsigned avail;
union REGS regs;
int rc, swapping;
strcpy(execfn,exfn);
if (!spwn) {
swapping = -1;
} else {
/*----------------------------------------------------------------*
* Determine amount of free memory *
*-----------------------------------------------------------------*/
regs.x.ax = 0x4800;
regs.x.bx = 0xffff;
intdos (®s, ®s);
avail = regs.x.bx;
/*----------------------------------------------------------------*
* No swapping if available memory > needed *
*-----------------------------------------------------------------*/
if(needed < avail) {
swapping = 0;
} else {
/* Swapping necessary, use 'TEMP' environment variable */
/* to determine swap file path if defined. */
swapping = spwn;
if (spwn & USE_FILE) {
char *cp;
if((cp = getenv("TEMP")) == NULL)
cp = "";
strcpy(swapfn,cp);
if (_osmajor >= 3) {
swapping |= CREAT_TEMP;
} else {
swapping = 0;
}
}
}
}
/* All set up, ready to go. */
if (swapping > 0) {
swapping |= DONT_SWAP_ENV;
if((rc = prep_swap(swapping,swapfn)) < 0)
return RC_PREPERR | -rc;
}
return (do_spawn(swapping,execfn,epars,0,0));
}
static unsigned near
dos_prepare(Doslock *dl)
{
#ifdef ASY
int i;
struct asy *asyp;
#endif
/*-------------------------------------------------------------------*
* save the current screen layout *
*--------------------------------------------------------------------*/
gettextinfo(&dl->tr);
dl->sbuf = mxallocw(2 * dl->tr.screenheight * dl->tr.screenwidth);
gettext(dl->tr.winleft, dl->tr.wintop,dl->tr.winright, dl->tr.winbottom,dl->sbuf);
/*-------------------------------------------------------------------*
* temporarily suspend all our irq's *
* SEE THE CHANGES IN THE PARTICULAR xxx_init() and xxx_stop rtns. *
* dk5dc *
*--------------------------------------------------------------------*/
#ifdef ASY
for(i = 0; i < ASY_MAX; i++) { /* scan the asy structures */
asyp = &Asy[i];
if(asyp->iface == NULLIF)
continue;
asy_stop(asyp->iface,1); /* note:changes in 8250.c dk5dc */
}
#endif
#ifdef SCC
sccstop(); /* brute force ! */
#endif
#ifdef PACKET
pkt_suspend(); /* see pktdrvr.c */
#endif
stop_timer(&Statustimer);
uchtimer(); /* disconnect the timer interrupt*/
return(1);
}
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
static void near
dos_restore(Doslock *dl)
{
#ifdef ASY
int i;
#endif
#ifdef PACKET
extern INTERRUPT (*Pkvec[])();
#endif
/*-------------------------------------------------------------------*
* restore the screen layout *
*--------------------------------------------------------------------*/
puttext(dl->tr.winleft, dl->tr.wintop,dl->tr.winright, dl->tr.winbottom,dl->sbuf);
gotoxy(dl->tr.curx,dl->tr.cury);
xfree(dl->sbuf);
/*-------------------------------------------------------------------*
* restore our irq's *
* SEE THE CHANGES IN THE PARTICULAR xxx_init() and xxx_stop() rtns. *
* dk5dc *
*--------------------------------------------------------------------*/
#ifdef ASY
for(i = 0; i < ASY_MAX; i++) {
struct asy *asyp = &Asy[i];
if(asyp->iface == NULLIF) {
continue;
}
asy_init(i,asyp->iface,0,0,0,0,asyp->speed,asyp->cts,asyp->rlsd);
}
#endif
#ifdef SCC
sccreact(); /* new function in scc.c dk5dc */
#endif
#ifdef PACKET
pkt_restore(); /* see pktdrvr.c */
#endif
chtimer(btick); /* rechain the timer interrupt */
start_timer(&Statustimer);
}
int
doswap(int argc,char **argv,void *p)
{
return setbool(&Swap,"EMS/XMS/FILE swapping",argc,argv);
}
/* Keyboard interrupt handler */
void
kbint(void)
{
int c, sig = FALSE;
while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE) {
sig = TRUE;
*Keyboard.wp++ = c;
if(Keyboard.wp == &Keyboard.buf[KBSIZE]) {
Keyboard.wp = Keyboard.buf;
}
Keyboard.cnt++;
}
if(sig) {
psignal(&Keyboard,0);
}
}
static int near
kbchar(void)
{
unsigned char c;
int i_state = dirps();
while(Keyboard.cnt == 0) {
pwait(&Keyboard);
}
Keyboard.cnt--;
restore(i_state);
c = *Keyboard.rp++;
if(Keyboard.rp == &Keyboard.buf[KBSIZE]) {
Keyboard.rp = Keyboard.buf;
}
return c;
}
/* Read characters from the keyboard, translating them to "real" ASCII.
* If none are ready, block. The F-10 key is special; translate it to -2.
*/
int
kbread(void)
{
int c;
if((c = kbchar()) == 0){
/* Lead-in to a special char */
switch(c = kbchar()){
case 3: /* NULL (bizzare!) */
c = 0;
break;
case 83: /* DEL key */
c = 0x7f;
break;
case 68: /* F10 - used as command escape */
c = -2;
break;
case 67: /* F9 used for trace screen */
c = -13;
break;
case 80: /* down */
c = 0x10;
break;
case 72: /* up */
c = 0x0f;
break;
default:
if(c > 58 && c < 67) { /* F1 to F8 */
c = (c - 56) * -1;
} else {
c = -1;
}
}
}
return c;
}
/* Install hardware interrupt handler.
* Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
* Note that bus line IRQ2 maps to IRQ9 on the AT
*/
int
setirq(unsigned irq,INTERRUPT (*handler)())
{
/* Set interrupt vector */
if(irq < 8) {
setvect(8 + irq,handler);
} else if(irq < 16 && getproc() > 5) {
setvect(0x70 + irq - 8,handler);
Isat = 1;
} else {
return -1;
}
return 0;
}
/* Return pointer to hardware interrupt handler.
* Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
*/
INTERRUPT
(*getirq(unsigned int irq))()
{
/* Set interrupt vector */
if(irq < 8){
return getvect(8+irq);
} else if(irq < 16){
return getvect(0x70 + irq - 8);
} else {
return NULLVIFP;
}
}
/* Disable hardware interrupt */
int
maskoff(unsigned irq)
{
if(irq < 8){
setbit(0x21,(1 << irq));
} else if(irq < 16){
irq -= 8;
setbit(0xa1,(1 << irq));
} else {
return -1;
}
return 0;
}
/* Enable hardware interrupt */
int
maskon(unsigned irq)
{
if(irq < 8) {
clrbit(0x21,(1 << irq));
} else if(irq < 16) {
irq -= 8;
clrbit(0xa1,(1 << irq));
} else {
return -1;
}
return 0;
}
/* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
int
getmask(unsigned irq)
{
if(irq < 8) {
return (inportb(0x21) & (1 << irq)) ? 0 : 1;
} else if(irq < 16) {
irq -= 8;
return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
} else {
return -1;
}
}
/* Called from assembler stub linked to BIOS interrupt 1C, called on each
* hardware clock tick. Signal a clock tick to the timer process.
*/
void
ctick(void)
{
Tick++;
psignal(&Tick,1);
}
/* Called from the timer process on every tick. NOTE! This function
* can NOT be called at interrupt time because it calls the BIOS
*/
void
pctick(void)
{
static long oldt = 0; /* Value of bioscnt() on last call */
static long days = 0; /* # of times bioscnt() has rolled over */
/* Update the time-since-boot */
long t = bioscnt();
if(t < oldt) {
/* bioscnt has rolled past midnight */
days++;
}
oldt = t;
Clock = (days * 0x1800b0L) + t - Starttime;
}
/* Set bit(s) in I/O port */
void
setbit(unsigned port,char bits)
{
outportb(port,inportb(port)|bits);
}
/* Clear bit(s) in I/O port */
void
clrbit(unsigned port,char bits)
{
outportb(port,(inportb(port) & ~bits));
}
/* Set or clear selected bits(s) in I/O port */
void
writebit(unsigned port,char mask,int val)
{
char x = inportb(port);
if(val) {
x |= mask;
} else {
x &= ~mask;
}
outportb(port,x);
}
/* Convert a pointer to a long integer */
long
ptol(void *p)
{
#ifndef TEST
return FP_SEG(p);
#else
long x = FP_OFF(p);
#ifdef LARGEDATA
x |= (long)FP_SEG(p) << 16;
#endif
return x;
#endif
}
#ifdef XXX
/* replaced by 'shtop' */
void *
ltop(long l)
{
unsigned seg = (unsigned)(l >> 16);
unsigned offset = (unsigned)l;
return (void *)MK_FP(seg,offset);
}
#endif
void *
shtop(char *s)
{
#ifdef MDEBUG
return (void *)MK_FP((unsigned)htol(s),16);
#else
return (void *)MK_FP((unsigned)htol(s),4);
#endif
}
#ifdef XXX
void
sysreset(void)
{
void far (*foo) __ARGS((void));
/* FFFF:0000 is hardware reset vector */
foo = MK_FP(0xffff,0);
(*foo)();
}
#endif
void
newscreen(struct session *sp)
{
if(sp != NULLSESSION) {
sp->screen = mxallocw(sizeof(struct screen));
}
}
void
freescreen(struct session *sp)
{
if(sp == NULLSESSION || sp->screen == NULLSCREEN) {
return;
}
if(sp->screen->save != NULLCHAR) {
xfree(sp->screen->save);
}
xfree(sp->screen);
sp->screen = NULLSCREEN; /* finish the job */
}
/* Save specified session screen and resume console screen */
void
swapscreen(struct session *old,struct session *new)
{
struct text_info tr;
struct session *sp;
int i, size;
char *oldsave, *newsave;
if(old == new)
return; /* Nothing to do */
gettextinfo(&tr);
size = 2 * tr.screenheight * tr.screenwidth;
if(old != NULLSESSION){
/* Save old screen */
if(old->screen->save == NULLCHAR)
old->screen->save = mxallocw(size);
if(old->screen->save != NULLCHAR) {
if(old->split) {
window(1,3,80,Nrows);
tr.winbottom = Nrows;
}
gettext(tr.winleft,tr.wintop,tr.winright,tr.winbottom,old->screen->save);
}
old->screen->row = tr.cury;
old->screen->col = tr.curx;
}
if(new != NULLSESSION){
/* Load new screen */
if(new->screen->save != NULLCHAR){
if(new->split) {
window(1,3,80,Nrows-2);
} else {
window(1,3,80,Nrows);
tr.winbottom = Nrows;
}
puttext(tr.winleft,tr.wintop,tr.winright,tr.winbottom,new->screen->save);
gotoxy(new->screen->col,new->screen->row);
/* Free the memory (saves 4K on a continuous basis) */
xfree(new->screen->save);
new->screen->save = NULLCHAR;
} else {
clrscr(); /* Start with a fresh slate */
if(new->split){
new->tsavex = 1;
new->bsavex = 1;
new->tsavey = 2;
new->bsavey = 24;
window(1,Nrows-1,80,Nrows);
cputs("_\b");
window(1,3,80,Nrows-2);
}
}
}
for(i = 0, sp = Sessions; i < Nsessions; sp++, i++) {
if(sp->type != FREE) {
if(sp->screen->save != NULLCHAR) {
newsave = mxallocw(size);
if(FP_SEG(newsave) < FP_SEG(sp->screen->save)) {
memcpy(newsave,sp->screen->save,size);
oldsave = sp->screen->save;
sp->screen->save = newsave;
xfree(oldsave);
} else {
xfree(newsave);
}
}
}
}
alert(Display,(void *)1); /* Wake him up */
}
void
display(int i,void *v1,void *v2)
{
/* This is very tricky code. Because the value of "Current" can
* change any time we do a pwait, we have to be careful to detect
* any change and go back and start again.
*/
for(;;){
int c;
struct session *sp = Current;
if(sp->morewait) {
pwait(&sp->row);
if(sp != Current || sp->row <= 0) {
/* Current changed value, or the user
* hasn't really hit a key
*/
continue;
}
/* Erase the prompt */
cputs("\r \r");
}
sp->morewait = 0;
if((c = rrecvchar(sp->output)) == -1){
/* the alert() in swapscreen will cause this to
* return -1 when current changes
*/
pwait(NULL); /* Prevent a nasty loop */
continue;
}
if(sp != Command) {
textattr(WHITE);
}
putch(c);
textattr(LIGHTGRAY);
if(sp->record != NULLFILE && c != '\r') {
fputc(c,sp->record);
}
if(sp->flowmode && c == '\n' && --sp->row <= 0) {
cputs("--More--");
sp->morewait = 1;
}
}
}
/* Return time since startup in milliseconds. If the system has an
* 8254 clock chip (standard on ATs and up) then resolution is improved
* below 55 ms (the clock tick interval) by reading back the instantaneous
* value of the counter and combining it with the global clock tick counter.
* Otherwise 55 ms resolution is provided.
*
* Reading the 8254 is a bit tricky since a tick could occur asynchronously
* between the two reads. The tick counter is examined before and after the
* hardware counter is read. If the tick counter changes, try again.
* Note: the hardware counter counts down from 65536.
*/
int32
msclock(void)
{
int32 hi;
int16 lo, count[4]; /* extended (48-bit) counter of timer clocks */
if(!Isat)
return Clock * MSPTICK;
do {
hi = Clock + Tick;
lo = clockbits();
} while(hi != Clock + Tick);
count[0] = 0;
count[1] = hi >> 16;
count[2] = hi;
count[3] = -lo;
longmul(11,4,count); /* The ratio 11/13125 is exact */
longdiv(13125,4,count);
return ((long)count[2] << 16) + count[3];
}
/* Return clock in seconds */
int32
secclock(void)
{
int32 hi;
int16 lo, count[4]; /* extended (48-bit) counter of timer clocks */
if(!Isat)
return (Clock * MSPTICK) / 1000L;
do {
hi = Clock + Tick;
lo = clockbits();
} while(hi != Clock + Tick);
count[0] = 0;
count[1] = hi >> 16;
count[2] = hi;
count[3] = -lo;
longmul(11,4,count); /* The ratio 11/13125 is exact */
longdiv(13125,4,count);
longdiv(1000,4,count); /* Convert to seconds */
return ((long)count[2] << 16) + count[3];
}